package com.androidbook.btdt_week9;

import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.location.Address;
import android.util.Log;

public class GeocoderEmul {
    // Lista donde se guardarás las dirección devueltas por la localización.

    List<Address> listAddress = new ArrayList<Address>();   
    
    public static final String DEBUG_TAG = "GeocoderEmul";
    public static final String XML_TAG_STATUS = "status";
    public static final String XML_TAG_LOCATION = "location";
    public static final String XML_TAG_LATITUDE = "lat";
    public static final String XML_TAG_LONGITUDE = "lng";
    public static final String XML_STATUS_OK = "OK";
    public static final String XML_ADDRESS = "formatted_address";
    public static final String XML_RESULT = "result";
    
    // Las dos siguientes variables conforman el principio y el final

    // de la llamada a google maps, en medio se colocará la direccion a buscar

    public static final String URL_MAP_1 = "http://maps.google.com/maps/api/geocode/xml?address=";
    public static final String URL_MAP_2 = "&sensor=false";

    public GeocoderEmul() {
    }
    
    public List<Address> getFromLocationName(String locationName, int maxResults) {
        proccessXml(locationName, maxResults);          
        return listAddress;
    }

    final protected void proccessXml(String address, int maxResults) {
        address = address.trim(); // eliminar espacios al principio y final

        try {

            Log.e(DEBUG_TAG, "Address is: " + address);
            
            // URLEncoder es necesario para caracteres no ascii
            String encodedUrl = URL_MAP_1 + URLEncoder.encode(address, "UTF-8") + URL_MAP_2;
            Log.e(DEBUG_TAG, "URL is: " + encodedUrl);
            URL mUrl = new URL(encodedUrl);

            // Crear y cargar el analizador (parser) con la URL
            XmlPullParser geoParser;
            try {
                geoParser = XmlPullParserFactory.newInstance()
                        .newPullParser();
                geoParser.setInput(mUrl.openStream(), null);
            } catch (XmlPullParserException e1) {
                geoParser = null;
                Log.e(DEBUG_TAG, "Failed to initialize pull parser", e1);
            } catch (IOException e) {
                geoParser = null;
                Log.e(DEBUG_TAG,
                        "IO Failure during pull parser initialization", e);
            }
            
            // Analizar y leer el XML
            if (geoParser != null) {
                try {
                    parseXML(geoParser, maxResults); // metodo de analisis y lectura

                } catch (XmlPullParserException e) {
                    Log.e(DEBUG_TAG, "Pull Parser failure", e);
                } catch (IOException e) {
                    Log.e(DEBUG_TAG, "IO Exception parsing XML", e);
                } catch (IndexOutOfBoundsException e) {
                    Log.e(DEBUG_TAG, "Index out of bounds Exception parsing XML", e);
                }
            }

        } catch (Exception e) {
            System.out.println(e.toString());
        }

    }

    
    // Queremos leer el contenido de los elementos lat y lng dentro de los elementos location
    // Nota: para ver el fichero xml, copiar el contenido de encodedUrl en un navegador
    //      se puede recoger de un log en proccessXml()
    protected void parseXML(XmlPullParser geoParser, int maxResults)
            throws XmlPullParserException, IOException, IndexOutOfBoundsException {
        
        int eventType = -1;
        int resultsCounter = 0;
        Address addressReturn = null;
        listAddress.clear(); // borramos la lista de usos previos

        Log.d(DEBUG_TAG, "maxResults: " + maxResults);
        
        // bucle principal
        while (eventType != XmlPullParser.END_DOCUMENT && resultsCounter <= maxResults) {
            String strName;
            if (eventType == XmlPullParser.START_TAG) {

                strName = geoParser.getName();
                Log.d(DEBUG_TAG, ":::::::::::::: <" + strName + "> ::::::::::::::::");

                if (strName.equals(XML_TAG_STATUS)) { // elementoXML status

                    String status = geoParser.nextText();
                    if(!status.equalsIgnoreCase(XML_STATUS_OK)) { // si no es una dirección existente

                        Log.e(DEBUG_TAG, "result is not Ok..."); //salimos del bucle principal

                        break;
                    }
                    else
                        Log.e(DEBUG_TAG, "result is Ok...");
                } else if(strName.equals(XML_RESULT)){
                	Log.d(DEBUG_TAG, "Nuevo resultado (" + resultsCounter + ")");
                	if (resultsCounter != maxResults) {
                		addressReturn = new Address(null); // añadimos un objeto Address nulo
                    	listAddress.add(addressReturn); // lo añadimos a la lista
                	}
                	
                	resultsCounter++;               //contador de elementos de la lista
                    
                } else if(strName.equals(XML_TAG_LOCATION)) { // elementoXML location
                	
                    eventType = geoParser.next(); // entramos en el contenido (otros elementos)

                    // bucle dentro de location
                    location:while (true)  {
                        if (eventType == XmlPullParser.START_TAG) {
                            strName = geoParser.getName();
                            
                            if(strName.equals(XML_TAG_LATITUDE)) { // elementoXML lat

                                // leemos el contenido del elementoXML
                                // que ahora es solo un texto, no hay otros elementosXML
                                String sLatitude = geoParser.nextText();                        
                                double latitude = Double.parseDouble(sLatitude);
                                
                                // actualizamos la lista
                                addressReturn = listAddress.get(resultsCounter - 1);
                                addressReturn.setLatitude(latitude);
                                listAddress.set(resultsCounter - 1, addressReturn);
                            }
                            else if(strName.equals(XML_TAG_LONGITUDE)) { // elementoXML lng

                                // leemos el contenido del elementoXML
                                // que ahora es solo un texto, no hay otros elementosXML
                                String sLongitude = geoParser.nextText();
                                double longitude = Double.parseDouble(sLongitude);
                                
                                // actualizamos la lista
                                addressReturn = listAddress.get(resultsCounter - 1); 
                                addressReturn.setLongitude(longitude);
                                listAddress.set(resultsCounter - 1, addressReturn);
                            }                                                       
                        }
                        else if(eventType == XmlPullParser.END_TAG) { // final de etiqueta

                            strName = geoParser.getName();
                            if(strName.equals(XML_TAG_LOCATION)) { // si final de location

                                addressReturn = listAddress.get(resultsCounter - 1);
                                Log.e(DEBUG_TAG, strName + " " + resultsCounter + ": (" +
                                        addressReturn.getLatitude() + ", " +
                                        addressReturn.getLongitude() + ")");
                                break location;     // salimos del bucle de location

                            }
                        }
                        eventType = geoParser.next(); // avanzamos dentro de location

                    }
                } else if (strName.equals(XML_ADDRESS)) {
                    // leemos el contenido del elementoXML
                    // que ahora es solo un texto, no hay otros elementosXML
                    String address = geoParser.nextText(); 
                    
                    String[] palabra = address.split("\\,");
                    String via = "";
                    String localidad = "";

                    int j=0;
                    while(j < palabra.length){
                    	Log.d(DEBUG_TAG, "Elemento [" + j + "]  = " + palabra[j]);
                    	if (j == 0) {
                    		via = palabra[j];
                    	} else {
                    		if (j < palabra.length -1) {
                    			localidad = localidad + palabra[j];
                    		}
                    	}
                    	j++;
                    }
                    
                    Log.d(DEBUG_TAG, "via = " + via);
                    Log.d(DEBUG_TAG, "localidad = " + localidad);
                    
                    Log.d(DEBUG_TAG, "address = " + address);
                	
                	// actualizamos la lista
                    Log.d(DEBUG_TAG, "resultsCounter = " + resultsCounter);
                    if (listAddress == null) {
                    	Log.e(DEBUG_TAG, "listAddress is null");
                    }
                    if (resultsCounter == 0) {
                    	Log.e(DEBUG_TAG, "Error muy grave. Probablemente falte etiqueta <result>");
                    }
                    addressReturn = listAddress.get(resultsCounter - 1);
                    Log.d(DEBUG_TAG, "obtener objeto de la lista");
                    addressReturn.setLocality(localidad);
                    Log.d(DEBUG_TAG, "insertada localidad");
                    addressReturn.setThoroughfare(via);
                    Log.d(DEBUG_TAG, "insertada via");
                    listAddress.set(resultsCounter - 1, addressReturn);
                    Log.d(DEBUG_TAG, "insertada address en lista otra vez");
                }
            }
            eventType = geoParser.next(); // avanzamos dentro del bucle principal

        }       
    }
}
